/*******************************************************************

    Author: Xiao
    Date: 2022/4/6 11:30

*******************************************************************/
package controller

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"io/ioutil"
	"math"
	"math/rand"
	"mcr/pkg/config"
	"mcr/pkg/dao"
	"mcr/pkg/logs"
	"mcr/pkg/middleware"
	"mcr/pkg/utils"
	socket "mcr/pkg/websocket"
	"net/http"
	url2 "net/url"
	"strconv"
	"time"
)

type searchReq struct {
	BasicReq
	IsHots  int    `json:"isHots"`
	Keyword string `json:"keyword"`
	RoomId  int    `json:"room_id"`
}

// 流转用的
type NowSong struct {
	User  UserInfo     `json:"user"`
	Song  dao.SongResp `json:"song"`
	Since int64        `json:"since"`
}

// 搜索歌曲
func SearchSong(ctx *gin.Context) {
	var sr searchReq
	err := ctx.ShouldBindJSON(&sr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	var songRs []dao.SongResp
	if sr.IsHots == 1 {
		list, err := dao.GetCacheString("week_song_play_rank")
		if err == nil {
			err := json.Unmarshal([]byte(list), &songRs)
			if err == nil {
				ctx.JSON(200, gin.H{
					"code": 200,
					"msg":  "缓存信息",
					"data": songRs,
				})
				return
			}
		}
		songRs, err = dao.GetHotSongs()
		if err != nil {
			logs.Log.Errorf("获取热门歌曲失败:%s", err)
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "获取热门歌曲失败",
			})
			return
		}
		songRsByte, err := json.Marshal(songRs)
		if err != nil {
			logs.Log.Errorf("缓存热门歌曲是编码失败:%s", err)
		}
		err = dao.SetCacheString("week_song_play_rank", string(songRsByte), 30*time.Second)
		if err != nil {
			logs.Log.Errorf("缓存热门歌曲失败:%s", err)
		}
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "获取成功",
			"data": songRs,
		})
		return
	}
	rand.Seed(time.Now().UnixMilli())
	beginKeywords := []string{"周杰伦", "林俊杰", "张学友", "林志炫", "梁静茹", "周华健", "华晨宇", "张宇", "张杰", "李宇春", "六哲", "阿杜", "伍佰", "五月天", "毛不易", "梁咏琪", "艾薇儿", "陈奕迅", "李志", "胡夏"}
	if sr.Keyword == "" {
		sr.Keyword = beginKeywords[rand.Intn(len(beginKeywords)-1)]
	}
	kwToken := rand.Int31n(99999999)
	client := &http.Client{}
	url := "http://bd.kuwo.cn/api/www/search/searchMusicBykeyWord?pn=1&rn=50&key=" + url2.QueryEscape(sr.Keyword)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		logs.Log.Errorf("查询歌曲失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "搜索失败,建议重试",
		})
		return
	}
	req.Header.Set("Content-Type", "application/json; charset=utf-8")
	//req.Header.Set("Cookie",fmt.Sprintf("kw_token=%d",kwToken))
	req.Header.Set("csrf", fmt.Sprintf("%d", kwToken))
	req.Header.Set("Referer", "http://bd.kuwo.cn")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36")
	req.AddCookie(&http.Cookie{Name: "kw_token", Value: fmt.Sprintf("%d", kwToken)})
	resp, err := client.Do(req)
	if err != nil {
		logs.Log.Errorf("查询歌曲失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "搜索失败,建议重试",
		})
		return
	}
	defer resp.Body.Close()
	respByte, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logs.Log.Errorf("解析歌曲响应:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "搜索失败,建议重试",
		})
		return
	}
	respMap := make(map[string]interface{})
	err = json.Unmarshal(respByte, &respMap)
	if err != nil {
		logs.Log.Errorf("解析歌曲Map:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "搜索失败,建议重试",
		})
		return
	}
	if code, ok := respMap["code"]; ok {
		if code == 200.0 {
			if data, ok := respMap["data"]; ok {
				if list, ok := data.(map[string]interface{})["list"]; ok {
					for _, l := range list.([]interface{}) {
						var sr dao.SongResp
						sr.Name = l.(map[string]interface{})["name"].(string)
						sr.Pic = l.(map[string]interface{})["pic"].(string)
						sr.Singer = l.(map[string]interface{})["artist"].(string)
						sr.Length = int(l.(map[string]interface{})["duration"].(float64))
						sr.Mid = int64(l.(map[string]interface{})["rid"].(float64))
						sr.Album = l.(map[string]interface{})["album"].(string)
						songRs = append(songRs, sr)
						srByte, err := json.Marshal(&sr)
						if err != nil {
							logs.Log.Errorf("编码音乐详细信息错误:%s", err)
						}
						err = dao.SetCacheString(fmt.Sprintf("song_detail_%d", sr.Mid), string(srByte), 3600*time.Second)
						if err != nil {
							logs.Log.Errorf("保存音乐详细信息错误:%s", err)
						}
					}
				}
			}
		}
	} else {
		logs.Log.Errorf("获取歌曲响应失败:%s", respMap["msg"])
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "搜索失败,建议重试",
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "获取成功",
		"data": songRs,
	})
	return
}

type operateSongReq struct {
	BasicReq
	RoomId int   `json:"room_id" binding:"required"`
	Mid    int64 `json:"mid" binding:"required"`
	At     int   `json:"at"`
}

// 添加到我的音乐
func AddMySong(ctx *gin.Context) {
	var osr operateSongReq
	err := ctx.ShouldBindJSON(&osr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if osr.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(osr.AccessToken)
	if err != nil {
		logs.Log.Errorf("用户信息获取失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	u, err := GetUserData(uid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	r, err := dao.GetRoomById(osr.RoomId)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "房间信息查询失败!",
		})
		return
	}
	_, err = dao.GetSongByMidAndUser(osr.Mid, uid)
	if err == nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "你已经搜藏过这首歌!",
		})
		return
	}
	sByte, err := dao.GetCacheString(fmt.Sprintf("song_detail_%d", osr.Mid))
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "歌曲信息获取失败，收藏失败!",
		})
		return
	}
	var sr dao.SongResp
	err = json.Unmarshal([]byte(sByte), &sr)
	if err != nil {
		logs.Log.Errorf("解析歌曲信息:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "解析歌曲信息，收藏失败!",
		})
		return
	}
	var s = dao.Song{
		SongMid:    sr.Mid,
		SongName:   sr.Name,
		SongSinger: sr.Singer,
		SongPic:    sr.Pic,
		SongLength: sr.Length,
		SongUser:   uid,
	}
	_, err = dao.CreateSong(s)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "收藏失败!",
		})
		return
	}
	msg := make(map[string]interface{})
	msg["type"] = "system"
	msg["time"] = time.Now().Format("15:04:05")
	msg["content"] = u.UserName + " 收藏了当前播放的歌曲"
	socket.SendMsgToRoom(r.RoomId, msg)
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "歌曲搜藏成功，快去你的已点列表看看吧!",
	})
	return
}

// 删除我的音乐
func DeleteMySong(ctx *gin.Context) {
	var osr operateSongReq
	err := ctx.ShouldBindJSON(&osr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if osr.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(osr.AccessToken)
	if err != nil {
		logs.Log.Errorf("用户信息获取失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	err = dao.DeleteSong(osr.Mid, uid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "删除歌单的歌曲失败,请重试!",
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "删除歌单的歌曲成功",
	})
	return
}

type listMySongReq struct {
	BasicReq
	Page    int `json:"page" `
	PerPage int `json:"per_page" `
}

// 获取我的音乐列表
func GetMySongList(ctx *gin.Context) {
	var lmsr listMySongReq
	err := ctx.ShouldBindJSON(&lmsr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if lmsr.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(lmsr.AccessToken)
	if err != nil {
		logs.Log.Errorf("用户信息获取失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	if lmsr.Page == 0 {
		lmsr.Page = 1
	}
	if lmsr.PerPage == 0 {
		lmsr.PerPage = 20
	}
	srs, err := dao.GetSongList(uid, lmsr.Page, lmsr.PerPage)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取失败!",
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "获取成功!",
		"data": srs,
	})
	return
}

type userListReq struct {
	BasicReq
	UserId int  `json:"user_id" `
	IsAll  bool `json:"is_all"`
}

// 获取我的音乐列表
func GetUserSongs(ctx *gin.Context) {
	var ulr userListReq
	err := ctx.ShouldBindJSON(&ulr)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if ulr.UserId == 0 {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "该用户为游客，无音乐列表.",
		})
		return
	}

	srs, err := dao.GetUserSongList(ulr.UserId, ulr.IsAll)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取失败!",
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "获取成功!",
		"data": srs,
	})
	return
}

type lrcReq struct {
	BasicReq
	Mid int `json:"mid"  binding:"required"`
}
type lrcResp struct {
	LineLyric string `json:"lineLyric"`
	Time      string `json:"time"`
}

// 获取歌词
func GetLrc(ctx *gin.Context) {
	var lr lrcReq
	err := ctx.ShouldBindJSON(&lr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	data := make(map[string]interface{})
	if lr.Mid < 0 {
		data["lineLyric"] = "歌曲为用户上传,暂无歌词"
		data["time"] = 0
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "歌曲为用户上传,暂无歌词",
			"data": data,
		})
		return
	}
	kwToken := rand.Int31n(99999999)
	client := &http.Client{}
	url := fmt.Sprintf("http://m.kuwo.cn/newh5/singles/songinfoandlrc?musicId=%d", lr.Mid)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		logs.Log.Errorf("查询歌词失败:%s", err)
		data["lineLyric"] = "很尴尬呀,没有查到歌词~"
		data["time"] = 0
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "很尴尬呀,没有查到歌词~",
			"data": data,
		})
		return
	}
	req.Header.Set("Content-Type", "application/json; charset=utf-8")
	//req.Header.Set("Cookie",fmt.Sprintf("kw_token=%d",kwToken))
	req.Header.Set("csrf", fmt.Sprintf("%d", kwToken))
	req.Header.Set("Referer", "http://bd.kuwo.cn")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36")
	req.AddCookie(&http.Cookie{Name: "kw_token", Value: fmt.Sprintf("%d", kwToken)})
	resp, err := client.Do(req)
	if err != nil {
		logs.Log.Errorf("查询歌词失败:%s", err)
		data["lineLyric"] = "很尴尬呀,没有查到歌词~"
		data["time"] = 0
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "很尴尬呀,没有查到歌词~",
			"data": data,
		})
		return
	}
	defer resp.Body.Close()
	respByte, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logs.Log.Errorf("解析歌词失败:%s", err)
		data["lineLyric"] = "很尴尬呀,没有查到歌词~"
		data["time"] = 0
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "很尴尬呀,没有查到歌词~",
			"data": data,
		})
		return
	}
	respMap := make(map[string]interface{})
	err = json.Unmarshal(respByte, &respMap)
	if err != nil {
		logs.Log.Errorf("解析歌词Map失败:%s", err)
		data["lineLyric"] = "很尴尬呀,没有查到歌词~"
		data["time"] = 0
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "很尴尬呀,没有查到歌词~",
			"data": data,
		})
		return
	}
	lrs := []lrcResp{{LineLyric: "歌词加载成功", Time: "0"}}
	if status, ok := respMap["status"]; ok {
		if status == 200.0 {
			if data, ok := respMap["data"]; ok {
				if list, ok := data.(map[string]interface{})["lrclist"]; ok {
					for _, l := range list.([]interface{}) {
						lr := lrcResp{
							LineLyric: l.(map[string]interface{})["lineLyric"].(string),
							Time:      l.(map[string]interface{})["time"].(string),
						}
						lrs = append(lrs, lr)
					}
					ctx.JSON(200, gin.H{
						"code": 200,
						"msg":  "获取成功",
						"data": lrs,
					})
					return
				}
			}
		}
	}
	logs.Log.Errorf("获取歌词响应失败:%s", respMap["msg"])
	data["lineLyric"] = "很尴尬呀,没有查到歌词~"
	data["time"] = 0
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "很尴尬呀,没有查到歌词~",
		"data": data,
	})
	return
}

// 获取歌曲
func PlayUrl(ctx *gin.Context) {
	var lr lrcReq
	err := ctx.ShouldBindJSON(&lr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	cachName := fmt.Sprintf("song_play_temp_url_%d", lr.Mid)
	url, err := dao.GetCacheString(cachName)
	if err == nil {
		ctx.Redirect(http.StatusMovedPermanently, url)
		return
	}
	if lr.Mid < 0 {
		a, err := dao.GetAttach(0 - lr.Mid)
		if err != nil {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "没找到歌曲文件",
			})
			return
		}
		path := config.ConfigValue.StorePath + a.AttachPath
		err = dao.SetCacheString(cachName, path, 30*time.Second)
		if err != nil {
			logs.Log.Errorf("暂存本地音乐播放路径失败:%s", err)
		}
		ctx.Redirect(http.StatusMovedPermanently, path)
		return
	}
	gurl := fmt.Sprintf("http://m.kuwo.cn/newh5app/api/mobile/v1/music/src/%d", lr.Mid)
	res, err := http.Get(gurl)
	if err != nil {
		logs.Log.Errorf("获取播放地址失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取播放地址失败了",
		})
		return
	}
	defer res.Body.Close()
	bodyByte, err := ioutil.ReadAll(res.Body)
	if err != nil {
		logs.Log.Errorf("读取播放地址失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取播放地址失败了",
		})
		return
	}
	body := make(map[string]interface{})
	err = json.Unmarshal(bodyByte, &body)
	if err != nil {
		logs.Log.Errorf("解析播放地址失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取播放地址失败了",
		})
		return
	}
	if code, ok := body["code"]; ok {
		if code == 200.0 {
			if data, ok := body["data"]; ok {
				if u, ok := data.(map[string]interface{})["url"]; ok {
					err = dao.SetCacheString(cachName, u.(string), 30*time.Second)
					if err != nil {
						logs.Log.Errorf("音乐播放路径缓存失败:%s", err)
					}
					ctx.Redirect(http.StatusMovedPermanently, u.(string))
					return
				}
			}
		}
	}
	ctx.JSON(200, gin.H{
		"code": 500,
		"msg":  "获取播放地址失败了",
	})
	return
}

// 获取歌曲
func PlayUrlGet(ctx *gin.Context) {
	midStr := ctx.Query("mid")
	mid, err := strconv.ParseInt(midStr, 10, 64)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "参数无效",
		})
		return
	}
	cachName := fmt.Sprintf("song_play_temp_url_%d", mid)
	url, err := dao.GetCacheString(cachName)
	if err == nil {
		ctx.Redirect(http.StatusMovedPermanently, url)
		return
	}
	if mid < 0 {
		a, err := dao.GetAttach(0 - int(mid))
		if err != nil {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "没找到歌曲文件",
			})
			return
		}
		path := config.ConfigValue.StorePath + a.AttachPath
		err = dao.SetCacheString(cachName, path, 30*time.Second)
		if err != nil {
			logs.Log.Errorf("暂存本地音乐播放路径失败:%s", err)
		}
		ctx.Redirect(http.StatusMovedPermanently, path)
		return
	}
	gurl := fmt.Sprintf("http://m.kuwo.cn/newh5app/api/mobile/v1/music/src/%d", mid)
	res, err := http.Get(gurl)
	if err != nil {
		logs.Log.Errorf("获取播放地址失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取播放地址失败了",
		})
		return
	}
	defer res.Body.Close()
	bodyByte, err := ioutil.ReadAll(res.Body)
	if err != nil {
		logs.Log.Errorf("读取播放地址失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取播放地址失败了",
		})
		return
	}
	body := make(map[string]interface{})
	err = json.Unmarshal(bodyByte, &body)
	if err != nil {
		logs.Log.Errorf("解析播放地址失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取播放地址失败了",
		})
		return
	}
	if code, ok := body["code"]; ok {
		if code == 200.0 {
			if data, ok := body["data"]; ok {
				if u, ok := data.(map[string]interface{})["url"]; ok {
					err = dao.SetCacheString(cachName, u.(string), 30*time.Second)
					if err != nil {
						logs.Log.Errorf("音乐播放路径缓存失败:%s", err)
					}
					ctx.Redirect(http.StatusMovedPermanently, u.(string))
					return
				}
			}
		}
	}
	ctx.JSON(200, gin.H{
		"code": 500,
		"msg":  "获取播放地址失败了",
	})
	return
}

type listReq struct {
	BasicReq
	Rid int `json:"room_id"  binding:"required"`
}
type ListSong struct {
	User      UserInfo     `json:"user"`
	Song      dao.SongResp `json:"song"`
	At        interface{}  `json:"at"`
	PushCount int          `json:"push_count"`
	PushTime  int64        `json:"push_time"`
	Since     int64        `json:"since"`
}

// 从缓存中获取音乐列表
func GetSongListFromCache(rid int) []ListSong {
	var lss []ListSong
	listStr, err := dao.GetCacheString(fmt.Sprintf("SongList_%d", rid))
	if err == nil {
		err = json.Unmarshal([]byte(listStr), &lss)
		if err != nil {
			logs.Log.Errorf("解码歌曲列表失败:%s", err)
		}
	}
	return lss
}

// 获取歌曲详情信息
func GetSongDetailByMid(mid int64) (dao.SongResp, error) {
	var songR dao.SongResp
	song, err := dao.GetCacheString(fmt.Sprintf("song_detail_%d", mid))
	if err == nil {
		if err = json.Unmarshal([]byte(song), &songR); err == nil {
			if songR.Mid != 0 {
				return songR, nil
			}
		} else {
			logs.Log.Errorf("解析缓存中的音乐详情失败:%s", err)
		}
	}
	s, err := dao.GetSongByMid(mid)
	if err != nil {
		return songR, errors.New("歌曲数据获取失败,请重新搜索后点歌")
	}
	songR.Mid = s.SongMid
	songR.Name = s.SongName
	songR.Length = s.SongLength
	songR.Pic = s.SongPic
	songR.Singer = s.SongSinger
	return songR, nil
}

// 已点列表
func SongList(ctx *gin.Context) {
	var lr listReq
	err := ctx.ShouldBindJSON(&lr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	var lss []ListSong
	lss = GetSongListFromCache(lr.Rid)
	if len(lss) == 0 {
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "获取成功",
			"data": []ListSong{},
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "获取成功",
		"data": lss,
	})
	return
}

// 添加歌曲至已点
func AddSong(ctx *gin.Context) {
	var osr operateSongReq
	err := ctx.ShouldBindJSON(&osr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if osr.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(osr.AccessToken)
	if err != nil {
		logs.Log.Errorf("用户信息获取失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	u, err := GetUserData(uid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	r, err := dao.GetRoomById(osr.RoomId)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "房间信息查询失败!",
		})
		return
	}
	if r.RoomType != 1 && r.RoomType != 4 {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "该房间下不允许点歌!",
		})
		return
	}
	if _, err := dao.GetCacheString(fmt.Sprintf("songdown_room_%d_user_%d", osr.RoomId, uid)); err == nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "你被房主禁止了点歌权限!",
		})
		return
	}
	var sl ListSong
	sl.Song, err = GetSongDetailByMid(osr.Mid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "歌曲数据获取失败,请重新搜索后点歌!",
		})
		return
	}
	if sl.Song.Mid == 0 {
		s, err := dao.GetSongByMid(osr.Mid)
		if err != nil {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "歌曲数据获取失败,请重新搜索后点歌!",
			})
			return
		}
		sl.Song.Mid = s.SongMid
		sl.Song.Name = s.SongName
		sl.Song.Singer = s.SongSinger
		sl.Song.Pic = s.SongPic
		sl.Song.Length = s.SongLength
		sl.Song.Album = s.SongName
	}
	if sl.Song.Mid > 0 {
		gurl := fmt.Sprintf("http://wapi.kuwo.cn/api/www/music/musicInfo?mid=%d&httpsStatus=1", osr.Mid)
		res, err := http.Get(gurl)
		if err != nil {
			logs.Log.Errorf("歌曲信息获取失败:%s", err)
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "歌曲信息获取失败",
			})
			return
		}
		defer res.Body.Close()
		bodyByte, err := ioutil.ReadAll(res.Body)
		if err != nil {
			logs.Log.Errorf("读取歌曲信息失败:%s", err)
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "歌曲信息获取失败",
			})
			return
		}
		body := make(map[string]interface{})
		err = json.Unmarshal(bodyByte, &body)
		if err != nil {
			logs.Log.Errorf("解析歌曲信息失败:%s", err)
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "歌曲信息获取失败",
			})
			return
		}
		if code, ok := body["code"]; ok {
			if code == 200.0 {
				if data, ok := body["data"]; ok {
					if pic, ok := data.(map[string]interface{})["pic"]; ok {
						updateMap := make(map[string]interface{})
						updateMap["song_pic"] = pic.(string)
						err = dao.UpdateSongByMid(osr.Mid, updateMap)
						if err != nil {
							logs.Log.Errorf("更新音乐头像错误:%s", err)
						}
						sl.Song.Pic = pic.(string)
						err = dao.SetCacheString(fmt.Sprintf("song_picture_%d", osr.Mid), pic.(string), 0)
						if err != nil {
							logs.Log.Errorf("更新音乐头像缓存失败:%s", err)
						}
						songByte, err := json.Marshal(sl.Song)
						if err == nil {
							err = dao.SetCacheString(fmt.Sprintf("song_detail_%d", osr.Mid), string(songByte), 3600*time.Second)
							if err != nil {
								logs.Log.Errorf("缓存音乐详情信息失败:%s", err)
							}
						} else {
							logs.Log.Errorf("编码音乐详情信息失败:%s", err)
						}
					}
				} else {
					ctx.JSON(200, gin.H{
						"code": 500,
						"msg":  "歌曲信息获取失败",
					})
					return
				}
			} else {
				logs.Log.Errorf("歌曲信息获取失败:%s", body["msg"])
				ctx.JSON(200, gin.H{
					"code": 500,
					"msg":  "歌曲信息获取失败",
				})
				return
			}
		} else {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "歌曲信息获取失败",
			})
			return
		}

	}
	if osr.At == 0 {
		sl.At = false
	} else {
		if sl.At == uid {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "“自己给自己送歌，属实不高端”——佚名!",
			})
			return
		}
		atUser, err := GetUserData(osr.At)
		if err != nil {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "被送歌人信息查询失败!",
			})
			return
		}
		sl.At = atUser
	}
	sls := GetSongListFromCache(osr.RoomId)
	mysong := 0
	for _, sl := range sls {
		if sl.User.UserId == uid {
			mysong++
		}
		if sl.Song.Mid == osr.Mid {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  fmt.Sprintf("歌曲《%s》正在等待播放呢!", sl.Song.Name),
			})
			return
		}
	}
	addSongCdTime := r.RoomAddsongcd
	if !utils.GetIsAdmin(u.UserGroup) && uid != r.RoomUser && !IsVip(osr.RoomId, uid) {
		if r.RoomAddsong == 1 {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "点歌失败,当前房间仅房主可点歌",
			})
			return
		}
		if addSongLastTimeStr, err := dao.GetCacheString(fmt.Sprintf("song_add_%d_user_%d", osr.RoomId, uid)); err == nil {
			if addSongLastTime, err := strconv.ParseInt(addSongLastTimeStr, 10, 64); err == nil {
				addSongNeedTime := int64(addSongCdTime) - (time.Now().Unix() - addSongLastTime)
				if addSongNeedTime > 0 {
					ctx.JSON(200, gin.H{
						"code": 500,
						"msg":  fmt.Sprintf("点歌太频繁，请%ds后再试", addSongNeedTime),
					})
					return
				}
			}
		}
		if mysong >= r.RoomAddcount {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  fmt.Sprintf("你还有%d首歌没有播，请稍候再点歌吧~", mysong),
			})
			return
		}
	}
	if len(sls) == 1 && sls[0].User.UserId == 1 {
		sls = []ListSong{}
	}
	sl.User = u
	sls = append(sls, sl)
	slsByte, err := json.Marshal(sls)
	if err != nil {
		logs.Log.Errorf("编码音乐列表失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "添加音乐失败",
		})
		return
	}
	err = dao.SetCacheString(fmt.Sprintf("SongList_%d", r.RoomId), string(slsByte), 86400*time.Second)
	if err != nil {
		logs.Log.Errorf("设置音乐列表缓存失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "添加音乐失败",
		})
		return
	}
	sendMsg := make(map[string]interface{})
	sendMsg["user"] = u
	sendMsg["song"] = sl.Song
	sendMsg["at"] = sl.At
	sendMsg["type"] = "addSong"
	sendMsg["count"] = len(sls)
	sendMsg["time"] = time.Now().Format("15:04:05")
	socket.SendMsgToRoom(r.RoomId, sendMsg)
	os, err := dao.GetSongByMidAndUser(osr.Mid, uid)
	if err != nil {
		ns := dao.Song{
			SongSinger: sl.Song.Singer,
			SongPic:    sl.Song.Pic,
			SongMid:    sl.Song.Mid,
			SongName:   sl.Song.Name,
			SongLength: sl.Song.Length,
			SongUser:   uid,
			SongPlay:   1,
			SongWeek:   1,
		}
		_, err = dao.CreateSong(ns)
		if err != nil {
			logs.Log.Errorf("点歌时创建音乐失败:%s", err)
		}
	} else {
		updateMap := make(map[string]interface{})
		updateMap["song_play"] = os.SongPlay + 1
		updateMap["song_week"] = os.SongWeek + 1
		err = dao.UpdateSongBySid(os.SongId, updateMap)
		if err != nil {
			logs.Log.Errorf("修改点歌次数失败:%s", err)
		}
	}
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  fmt.Sprintf("歌曲%s已经添加到播放列表！", sl.Song.Name),
		"data": sl.Song,
	})
	return
}

// 播放歌曲
func PlaySong(ctx *gin.Context) {
	var osr operateSongReq
	err := ctx.ShouldBindJSON(&osr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if osr.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(osr.AccessToken)
	if err != nil {
		logs.Log.Errorf("用户信息获取失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	u, err := GetUserData(uid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	r, err := dao.GetRoomById(osr.RoomId)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "房间信息查询失败!",
		})
		return
	}
	if r.RoomType != 4 {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "该房间下不允许播放!",
		})
		return
	}
	if !utils.GetIsAdmin(uid) && r.RoomUser != uid && !IsVip(osr.RoomId, uid) {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "你没有权限播放!",
		})
		return
	}
	// 判断是否在播放列表中
	sls := GetSongListFromCache(osr.RoomId)
	isPush := false
	pushIndex := 0
	for i, sl := range sls {
		if sl.Song.Mid == osr.Mid {
			isPush = true
			pushIndex = i
			break
		}
	}
	if isPush {
		sls = append(sls[:pushIndex], sls[pushIndex+1:]...)
	}

	var sl ListSong
	sl.Song, err = GetSongDetailByMid(osr.Mid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "歌曲数据获取失败,请重新搜索后点歌!",
		})
		return
	}
	if sl.Song.Mid > 0 {
		gurl := fmt.Sprintf("http://wapi.kuwo.cn/api/www/music/musicInfo?mid=%d&httpsStatus=1", osr.Mid)
		res, err := http.Get(gurl)
		if err != nil {
			logs.Log.Errorf("歌曲信息获取失败:%s", err)
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "歌曲信息获取失败",
			})
			return
		}
		defer res.Body.Close()
		bodyByte, err := ioutil.ReadAll(res.Body)
		if err != nil {
			logs.Log.Errorf("读取歌曲信息失败:%s", err)
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "歌曲信息获取失败",
			})
			return
		}
		body := make(map[string]interface{})
		err = json.Unmarshal(bodyByte, &body)
		if err != nil {
			logs.Log.Errorf("解析歌曲信息失败:%s", err)
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "歌曲信息获取失败",
			})
			return
		}
		if code, ok := body["code"]; ok {
			if code == 200.0 {
				if data, ok := body["data"]; ok {
					if pic, ok := data.(map[string]interface{})["pic"]; ok {
						updateMap := make(map[string]interface{})
						updateMap["song_pic"] = pic.(string)
						err = dao.UpdateSongByMid(osr.Mid, updateMap)
						if err != nil {
							logs.Log.Errorf("更新音乐头像错误:%s", err)
						}
						sl.Song.Pic = pic.(string)
						err = dao.SetCacheString(fmt.Sprintf("song_picture_%d", osr.Mid), pic.(string), 0)
						if err != nil {
							logs.Log.Errorf("更新音乐头像缓存失败:%s", err)
						}
						songByte, err := json.Marshal(sl.Song)
						if err == nil {
							err = dao.SetCacheString(fmt.Sprintf("song_detail_%d", osr.Mid), string(songByte), 3600*time.Second)
							if err != nil {
								logs.Log.Errorf("缓存音乐详情信息失败:%s", err)
							}
						} else {
							logs.Log.Errorf("编码音乐详情信息失败:%s", err)
						}
						return
					}
				}
			} else {
				logs.Log.Errorf("歌曲信息获取失败:%s", body["msg"])
				ctx.JSON(200, gin.H{
					"code": 500,
					"msg":  "歌曲信息获取失败",
				})
				return
			}
		}
	}
	var nsls []ListSong

	sl.At = false
	sl.User = u
	nsls = append(nsls, sl)
	nsls = append(nsls, sls...)

	slsByte, err := json.Marshal(nsls)
	if err != nil {
		logs.Log.Errorf("播放音乐时编码音乐列表失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "播放音乐失败",
		})
		return
	}
	err = dao.SetCacheString(fmt.Sprintf("SongList_%d", r.RoomId), string(slsByte), 86400*time.Second)
	if err != nil {
		logs.Log.Errorf("播放音乐时设置音乐列表缓存失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "播放音乐失败",
		})
		return
	}
	dao.DelCacheString(fmt.Sprintf("SongNow_%d", r.RoomId))
	os, err := dao.GetSongByMidAndUser(osr.Mid, uid)
	if err != nil {
		ns := dao.Song{
			SongSinger: sl.Song.Name,
			SongPic:    sl.Song.Pic,
			SongMid:    sl.Song.Mid,
			SongName:   sl.Song.Name,
			SongLength: sl.Song.Length,
			SongUser:   uid,
			SongPlay:   1,
			SongWeek:   1,
		}
		_, err = dao.CreateSong(ns)
		if err != nil {
			logs.Log.Errorf("播放音乐时创建音乐失败:%s", err)
		}
	} else {
		updateMap := make(map[string]interface{})
		updateMap["song_play"] = os.SongPlay + 1
		updateMap["song_week"] = os.SongWeek + 1
		err = dao.UpdateSongBySid(os.SongId, updateMap)
		if err != nil {
			logs.Log.Errorf("播放音乐时修改点歌次数失败:%s", err)
		}
	}
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "播放成功",
	})
	return
}

// 移除已点歌曲
func RemoveSong(ctx *gin.Context) {
	var osr operateSongReq
	err := ctx.ShouldBindJSON(&osr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if osr.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(osr.AccessToken)
	if err != nil {
		logs.Log.Errorf("用户信息获取失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	u, err := GetUserData(uid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	r, err := dao.GetRoomById(osr.RoomId)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "房间信息查询失败!",
		})
		return
	}
	ls := GetSongListFromCache(osr.RoomId)
	remove := false
	removeIndex := 0
	var removeSong ListSong
	for i, l := range ls {
		if l.Song.Mid == osr.Mid {
			removeSong = l
			removeIndex = i
			remove = true
			break
		}
	}
	if !remove {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "移除失败，歌曲ID不存在!",
		})
		return
	}

	if r.RoomUser != uid && !utils.GetIsAdmin(u.UserGroup) && uid != removeSong.User.UserId {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "你没有权限操作",
		})
		return
	}
	nls := append(ls[0:removeIndex], ls[removeIndex+1:]...)
	slsByte, err := json.Marshal(nls)
	if err != nil {
		logs.Log.Errorf("移除音乐时编码音乐列表失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "移除音乐失败",
		})
		return
	}
	err = dao.SetCacheString(fmt.Sprintf("SongList_%d", r.RoomId), string(slsByte), 86400*time.Second)
	if err != nil {
		logs.Log.Errorf("移除音乐时设置音乐列表缓存失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "移除音乐失败",
		})
		return
	}
	sendMsg := make(map[string]interface{})
	sendMsg["user"] = u
	sendMsg["song"] = removeSong.Song
	sendMsg["type"] = "removeSong"
	sendMsg["count"] = len(ls)
	sendMsg["time"] = time.Now().Format("15:04:05")
	socket.SendMsgToRoom(r.RoomId, sendMsg)
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "移除成功",
	})
	return
}

// 判断是不是vip
func IsVip(rid, uid int) bool {
	_, err := dao.GetCacheString(fmt.Sprintf("guest_room_%d_user_%d", rid, uid))
	if err != nil {
		return false
	}
	return true
}

// 切歌用户
type songPassUser struct {
	User int    `json:"user"`
	Name string `json:"name"`
	Ip   string `json:"ip"`
}

// 切歌
func PassSong(ctx *gin.Context) {
	var osr operateSongReq
	err := ctx.ShouldBindJSON(&osr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if osr.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(osr.AccessToken)
	if err != nil {
		logs.Log.Errorf("用户信息获取失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	u, err := GetUserData(uid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	r, err := dao.GetRoomById(osr.RoomId)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "房间信息查询失败!",
		})
		return
	}
	songResp, err := GetSongDetailByMid(osr.Mid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "歌曲数据获取失败,请重新搜索后点歌!",
		})
		return
	}
	now, err := dao.GetCacheString(fmt.Sprintf("SongNow_%d", osr.RoomId))
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "当前没有正在播放的歌曲!",
		})
		return
	}
	var nowSong ListSong
	err = json.Unmarshal([]byte(now), &nowSong)
	if err != nil {
		logs.Log.Errorf("获取正在播放的歌曲失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取正在播放的歌曲失败!",
		})
		return
	}
	//songListStr,err := dao.GetCacheString(fmt.Sprintf("SongList_%d",osr.RoomId))
	//if err != nil{
	//
	//}
	//var rtime int
	//timeStr,err := dao.GetCacheString(fmt.Sprintf("SongNextTime_%d",osr.RoomId))
	//if err == nil{
	//	rtime,_ = strconv.Atoi(timeStr)
	//}
	err = dao.SetCacheString(fmt.Sprintf("SongNextTime_%d", osr.RoomId), time.Now().Unix(), 0)
	if err != nil {
		logs.Log.Errorf("设置下次播放时间失败:%s", err)
	}
	// 需要投票
	if r.RoomUser != uid && !utils.GetIsAdmin(u.UserGroup) && nowSong.User.UserId != uid && !IsVip(osr.RoomId, uid) {
		if r.RoomVotepass == 0 {
			ctx.JSON(200, gin.H{
				"code": 200,
				"msg":  "该房间未开启投票切歌!",
			})
			return
		}
		//取消机器人的在线数
		onlineCount := r.RoomOnline - 2
		if onlineCount < 0 {
			onlineCount = 0
		}
		limitCount := int(math.Ceil(float64(onlineCount*r.RoomVotepercent) / 100))
		if limitCount > 10 {
			limitCount = 10
		}
		if limitCount < 1 {
			limitCount = 1
		}
		nextCountCachName := fmt.Sprintf("song_next_count_%d_mid_%d", r.RoomId, nowSong.Song.Mid)
		songNextUserCachName := fmt.Sprintf("song_next_user_%d", uid)
		var songNextCount, isMeNexted int
		if songNextCountStr, err := dao.GetCacheString(nextCountCachName); err == nil {
			songNextCount, _ = strconv.Atoi(songNextCountStr)
		}
		if isMeNextedStr, err := dao.GetCacheString(songNextUserCachName); err == nil {
			isMeNexted, _ = strconv.Atoi(isMeNextedStr)
		}
		if int64(isMeNexted) == nowSong.Song.Mid {
			ctx.JSON(200, gin.H{
				"code": 200,
				"msg":  fmt.Sprintf("已有%d人不想听,在线%d人不想听即可自动切歌", songNextCount, limitCount),
			})
			return
		}
		err = dao.SetCacheString(songNextUserCachName, nowSong.Song.Mid, 3600*time.Second)
		if err != nil {
			logs.Log.Errorf("设置切歌用户失败:%s", err)
		}
		songNextCount++
		sendMsg := make(map[string]interface{})
		sendMsg["content"] = fmt.Sprintf("有人表示不太喜欢当前播放的歌(%d/%d)", songNextCount, limitCount)
		sendMsg["type"] = "system"
		sendMsg["time"] = time.Now().Format("15:04:05")
		socket.SendMsgToRoom(osr.RoomId, sendMsg)
		if songNextCount >= limitCount {
			dao.DelCacheString(fmt.Sprintf("SongNow_%d", r.RoomId))
			sendMsg = make(map[string]interface{})
			sendMsg["content"] = fmt.Sprintf("在线用户(%d人)不想听这首歌，系统已自动切歌!", limitCount)
			sendMsg["type"] = "system"
			sendMsg["time"] = time.Now().Format("15:04:05")
			socket.SendMsgToRoom(osr.RoomId, sendMsg)
		}
		var songPassList []songPassUser
		if songPassListStr, err := dao.GetCacheString(fmt.Sprintf("song_pass_list_%d", r.RoomId)); err == nil {
			err := json.Unmarshal([]byte(songPassListStr), &songPassList)
			if err != nil {
				logs.Log.Errorf("解码切歌用户列表失败:%s", err)
			}
		}
		songPassList = append(songPassList, songPassUser{
			User: uid,
			Name: u.UserName,
			Ip:   ctx.Request.RemoteAddr,
		})
		if songPassListByte, err := json.Marshal(songPassList); err == nil {
			err = dao.SetCacheString(fmt.Sprintf("song_pass_list_%d", r.RoomId), string(songPassListByte), 3600*time.Second)
			if err != nil {
				logs.Log.Errorf("存储切歌用户列表失败:%s", err)
			}
		} else {
			logs.Log.Errorf("编码切歌用户列表失败:%s", err)
		}
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "你的不想听态度表态成功!",
		})
		return
	}

	err = dao.SetCacheString(fmt.Sprintf("SongNow_%d", osr.RoomId), "", 0)
	if err != nil {
		logs.Log.Errorf("设置下次播放时间失败:%s", err)
	}
	sendMsg := make(map[string]interface{})
	sendMsg["user"] = u
	sendMsg["song"] = songResp
	sendMsg["type"] = "pass"
	sendMsg["time"] = time.Now().Format("15:04:05")
	socket.SendMsgToRoom(osr.RoomId, sendMsg)
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "切歌成功!",
	})
	return
}

// 顶歌
func PushSong(ctx *gin.Context) {
	var osr operateSongReq
	err := ctx.ShouldBindJSON(&osr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if osr.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(osr.AccessToken)
	if err != nil {
		logs.Log.Errorf("用户信息获取失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	u, err := GetUserData(uid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	r, err := dao.GetRoomById(osr.RoomId)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "房间信息查询失败!",
		})
		return
	}

	//var sl ListSong
	//sl.Song, err = GetSongDetailByMid(osr.Mid)
	//if err != nil {
	//	ctx.JSON(200, gin.H{
	//		"code": 500,
	//		"msg":  fmt.Sprintf("%s", err),
	//	})
	//	return
	//}
	sls := GetSongListFromCache(osr.RoomId)
	push := false
	var pushSong ListSong
	pushIndex := 0
	pushRole := r.RoomUser != uid && !utils.GetIsAdmin(u.UserGroup) && !IsVip(osr.RoomId, uid)
	for i, l := range sls {
		if l.Song.Mid == osr.Mid {
			if pushRole && l.User.UserId == uid {
				ctx.JSON(200, gin.H{
					"code": 500,
					"msg":  "不要顶你自己点的歌啦~",
				})
				return
			}
			pushIndex = i
			pushSong = l
			push = true
			sls[i].PushTime = time.Now().Unix()
			if pushRole {
				sls[i].PushCount++
			} else {
				sls[i].PushCount = 888
			}
			break
		}
	}
	if !push {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "顶歌失败，歌曲ID不存在",
		})
		return
	}
	limitCount := 0
	pushCacheTimeName := fmt.Sprintf("push_last_%d_%d", osr.RoomId, uid)
	if pushRole {
		pushCacheName := fmt.Sprintf("push_%d_%s_%d", osr.RoomId, time.Now().Format("2006-01-02"), uid)
		pushCount := r.RoomPushdaycount
		pushCache := 0
		var pushLastTime int64
		pushTimeLimit := r.RoomPushsongcd
		if pushCacheStr, err := dao.GetCacheString(pushCacheName); err == nil {
			pushCache, _ = strconv.Atoi(pushCacheStr)
		}
		if pushLastTimeStr, err := dao.GetCacheString(pushCacheTimeName); err == nil {
			pushLastTime, err = strconv.ParseInt(pushLastTimeStr, 10, 60)
		}
		if pushCache > pushCount {
			if pushCount > 0 {
				ctx.JSON(200, gin.H{
					"code": 500,
					"msg":  fmt.Sprintf("你的%d次顶歌机会已使用完啦", pushCount),
				})
				return
			} else {
				ctx.JSON(200, gin.H{
					"code": 500,
					"msg":  "当前房间房主设置不允许顶歌",
				})
				return
			}
		}
		limitCount = pushCount - pushCache
		if time.Now().Unix()-pushLastTime < int64(pushTimeLimit) {
			timeStr := ""
			minute := math.Floor(float64(int64(pushTimeLimit)-(time.Now().Unix()-pushLastTime)) / 60)
			if minute > 0 {
				timeStr += fmt.Sprintf("%.0f分", minute)
			}
			second := (int64(pushTimeLimit) - (time.Now().Unix() - pushLastTime)) % 60
			timeStr += fmt.Sprintf("%d秒", second)
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  fmt.Sprintf("顶歌太频繁啦，请%s后再试！", timeStr),
			})
			return
		}
		pushCache++
		err = dao.SetCacheString(pushCacheName, pushCache, 86400*time.Second)
		if err != nil {
			logs.Log.Errorf("顶歌时设置顶歌次数缓存失败:%s", err)
		}
	}
	var nsls = []ListSong{pushSong}
	nsls = append(nsls, sls[:pushIndex]...)
	nsls = append(nsls, sls[pushIndex+1:]...)
	slsByte, err := json.Marshal(nsls)
	if err != nil {
		logs.Log.Errorf("顶歌时编码音乐列表失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "顶歌失败",
		})
		return
	}
	err = dao.SetCacheString(fmt.Sprintf("SongList_%d", r.RoomId), string(slsByte), 86400*time.Second)
	if err != nil {
		logs.Log.Errorf("顶歌时设置音乐列表缓存失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "顶歌失败",
		})
		return
	}
	sendMsg := make(map[string]interface{})
	sendMsg["user"] = u
	sendMsg["song"] = pushSong.Song
	sendMsg["type"] = "push"
	sendMsg["count"] = len(sls)
	sendMsg["time"] = time.Now().Format("15:04:05")
	socket.SendMsgToRoom(r.RoomId, sendMsg)
	os, err := dao.GetSongByMidAndUser(osr.Mid, uid)
	if err != nil {
		ns := dao.Song{
			SongSinger: pushSong.Song.Name,
			SongPic:    pushSong.Song.Pic,
			SongMid:    pushSong.Song.Mid,
			SongName:   pushSong.Song.Name,
			SongLength: pushSong.Song.Length,
			SongUser:   uid,
			SongPlay:   1,
			SongWeek:   1,
		}
		_, err = dao.CreateSong(ns)
		if err != nil {
			logs.Log.Errorf("点歌时创建音乐失败:%s", err)
		}
	} else {
		updateMap := make(map[string]interface{})
		updateMap["song_play"] = os.SongPlay + 1
		updateMap["song_week"] = os.SongWeek + 1
		err = dao.UpdateSongBySid(os.SongId, updateMap)
		if err != nil {
			logs.Log.Errorf("修改点歌次数失败:%s", err)
		}
	}
	err = dao.SetCacheString(pushCacheTimeName, time.Now().Unix(), 86400*time.Second)
	if err != nil {
		logs.Log.Errorf("顶歌时设置顶歌时间缓存失败:%s", err)
	}
	if pushRole {
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  fmt.Sprintf("顶歌成功,今日剩余%d次顶歌机会!", limitCount),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "顶歌成功",
	})
	return
}

// 现在的歌曲
func NowTimeSong(ctx *gin.Context) {
	var lr listReq
	err := ctx.ShouldBindJSON(&lr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	r, err := dao.GetRoomById(lr.Rid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "房间信息查询失败!",
		})
		return
	}
	ls := GetSongListFromCache(lr.Rid)
	switch r.RoomType {
	case 1:
	case 4:
		if len(ls) > 1 {

		}
	default:

	}
	return
}

type AddSongReq struct {
	BasicReq
	Mid    int64  `json:"song_mid" binding:"required"`
	Name   string `json:"song_name" binding:"required"`
	Pic    string `json:"song_pic" binding:"required"`
	Singer string `json:"song_singer" binding:"required"`
	Length int    `json:"song_length" binding:"required"`
}

// 添加新音乐
func AddNewSong(ctx *gin.Context) {
	var asr AddSongReq
	err := ctx.ShouldBindJSON(&asr)
	if err != nil {
		logs.Log.Errorf("获取请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if asr.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(asr.AccessToken)
	if err != nil {
		logs.Log.Errorf("用户信息获取失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "用户信息获取失败!",
		})
		return
	}
	s := dao.Song{
		SongUser:   uid,
		SongMid:    0 - asr.Mid,
		SongPic:    asr.Pic,
		SongLength: asr.Length,
		SongSinger: asr.Singer,
		SongName:   asr.Name,
	}
	_, err = dao.CreateSong(s)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "歌曲添加失败",
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "歌曲添加成功",
	})
	return
}
